//
//  YHRouter.m
//  MoreCoin
//
//  Created by 林宁宁 on 2019/9/19.
//  Copyright © 2019 MoreCoin. All rights reserved.
//

#import "YHRouter.h"

#import <UIKit/UIKit.h>
#import <objc/runtime.h>

#import "YHRouter+Jump.h"
#import "YHRouter+Map.h"
#import "YHRouterParam.h"
#import "UIViewController+YHRouter.h"

#import "YHConstant+Null.h"
#import "UIButton+YH.h"

@import Bifrost;

UIViewController * YHFilterVCLoop(UIViewController * vc){
    UIViewController *result = vc;
    while (result.presentedViewController) {
        result = result.presentedViewController;
    }
    if ([result isKindOfClass:[UITabBarController class]]) {
        result = [(UITabBarController *)result selectedViewController];
    }
    if ([result isKindOfClass:[UINavigationController class]]) {
        result = [(UINavigationController *)result topViewController];
    }
    if ([result isKindOfClass:[UITabBarController class]]) {
        return YHFilterVCLoop(result);
    }
    if ([result isKindOfClass:[UINavigationController class]]) {
        return YHFilterVCLoop(result);
    }
    return result;
}

UIViewController * YHCurrentViewController(void){
    UIWindow * window = [[UIApplication sharedApplication] keyWindow];
    if (window.windowLevel != UIWindowLevelNormal){
        NSArray *windows = [[UIApplication sharedApplication] windows];
        for(UIWindow * tmpWin in windows){
            if (tmpWin.windowLevel == UIWindowLevelNormal){
                window = tmpWin;
                break;
            }
        }
    }
    UIViewController *result = YHFilterVCLoop(window.rootViewController);
    
    return result;
}

UINavigationController * YHCurrentNavigationViewController(void){
    
    UIViewController * currentVC = YHCurrentViewController();
    UIResponder *next = [currentVC.view nextResponder];
    do {
        if ([next isKindOfClass:[UINavigationController class]]) {
            return (UINavigationController *)next;
        }
        next = [next nextResponder];
    } while (next !=nil);

    UIWindow * window = [[UIApplication sharedApplication] keyWindow];
    if (window.windowLevel != UIWindowLevelNormal){
        NSArray *windows = [[UIApplication sharedApplication] windows];
        for(UIWindow * tmpWin in windows){
            if (tmpWin.windowLevel == UIWindowLevelNormal){
                window = tmpWin;
                break;
            }
        }
    }
    UIViewController *result = window.rootViewController;
    if ([result isKindOfClass:[UINavigationController class]]) {
        return (UINavigationController *)result;
    }
    
    while (result.presentedViewController) {
        result = result.presentedViewController;
    }
    if ([result isKindOfClass:[UITabBarController class]]) {
        result = [(UITabBarController *)result selectedViewController];
    }
    if ([result isKindOfClass:[UINavigationController class]]) {
        return (UINavigationController *)result;
    }
    
    return nil;
}


#pragma mark - YHRouterPrivite 在 UIViewController+YHRouter 中实现

@interface UIViewController (YHRouterPrivite)

/// router的传参
@property (retain, nonatomic) YHRouterParam * yh_routerParams;
/// 刷新界面
- (UIViewController *(^)(YHRouterParam * params))yh_reloadParams;
/// 该控制器只能有一个， 如果已有则刷新该控制器数据 并 pop回到该控制器
- (UIViewController *(^)(void))yh_singleton;
/// 判断控制器需要登录操作
/// vc中需在yh_routerNeedLoginFirst中声明 未声明则不做处理
- (UIViewController *(^)(void))yh_needLogin;

@end


#pragma mark - YHRouter

@implementation YHRouter

+ (instancetype)sharedManager {
    static YHRouter *router = nil;
    static dispatch_once_t onceToken;
    
    dispatch_once(&onceToken, ^{
        if (!router) {
            router = [[self alloc] init];
            router.navigationViewClass = UINavigationController.class;
            router.mapKeys = [NSMutableDictionary new];
            
            [Bifrost setExceptionHandler:^id _Nullable(NSException * _Nonnull exception) {
                NSLog(@"[Module] Exception:%@", exception);
                switch (exception.bf_exceptionCode) {
                    case BFExceptionUrlHandlerNotFound:
                        [router __errorHandle:YHRouterErrorCodeBFUrlHandlerNotFound reason:exception.reason];
                        break;
                    case BFExceptionModuleNotFoundException:
                        [router __errorHandle:YHRouterErrorCodeBFModuleNotFoundException reason:exception.reason];
                        break;
                    case BFExceptionAPINotFoundException:
                        [router __errorHandle:YHRouterErrorCodeBFAPINotFoundException reason:exception.reason];
                        break;
                    case BFExceptionFailedToRegisterModule:
                        [router __errorHandle:YHRouterErrorCodeBFFailedToRegisterModule reason:exception.reason];
                        break;
                    default:
                        break;
                }
                return nil;
            }];
        }
    });
    return router;
}

#pragma mark -

/// MARK: - Push Present

+ (UIViewController *)yh_pushKey:(NSString *)vcKey{
    return [YHRouter yh_pushKey:vcKey params:nil];
}
+ (UIViewController *)yh_pushKey:(NSString *)vcKey params:(YHRouterParam * _Nullable)params{
    return [YHRouter yh_pushKey:vcKey config:^UIViewController * _Nullable(UIViewController * _Nonnull vc) {
        return vc.yh_params(params);
    }];
}
+ (UIViewController *)yh_pushKey:(NSString *)vcKey config:(UIViewController * _Nullable (^ _Nullable)(UIViewController * _Nonnull))config{
    if(IsNonNull(vcKey)){
        UIViewController * vc = [YHRouter yh_controllerKey:vcKey];
        if(!vc){
            return nil;
        }
        if(config){
            id v = config(vc);
            if(!v){
                [[YHRouter sharedManager] __errorHandle:YHRouterErrorCodeConfigOpertionBreakOff reason:@"配置 返回空"];
                return nil;
            }
        }
        return vc.yh_push();
    }
    else{
        [[YHRouter sharedManager] __errorHandle:YHRouterErrorCodeKeyMapFormatError reason:@"vcKey 为空"];
        return nil;
    }
}



+ (UIViewController *)yh_presentKey:(NSString *)vcKey{
    return [YHRouter yh_presentKey:vcKey params:nil];
}
+ (UIViewController *)yh_presentKey:(NSString *)vcKey params:(YHRouterParam * _Nullable)params{
    return [YHRouter yh_presentKey:vcKey config:^UIViewController * _Nullable(UIViewController * _Nonnull vc) {
        return vc.yh_params(params);
    }];
}
+ (UIViewController *)yh_presentKey:(NSString *)vcKey config:(UIViewController * _Nullable(^ _Nullable)(UIViewController * vc))config{
    if(IsNonNull(vcKey)){
        UIViewController * vc = [YHRouter yh_controllerKey:vcKey];
        if(!vc){
            return nil;
        }
        if(config){
            id v = config(vc);
            if(!v){
                [[YHRouter sharedManager] __errorHandle:YHRouterErrorCodeConfigOpertionBreakOff reason:@"配置 返回空"];
                return nil;
            }
        }
        return vc.yh_present();
    }
    else{
        [[YHRouter sharedManager] __errorHandle:YHRouterErrorCodeKeyMapFormatError reason:@"vcKey 为空"];
        return nil;
    }
}



+ (void)yh_pushViewController:(UIViewController *)vc{
    /// 判断是否需要登录  是否唯一
    if(!vc.yh_singleton()){
        return;
    }
    if(!vc.yh_needLogin()){
        return;
    }
    if(!vc){
        return;
    }
    UINavigationController * navc = YHCurrentNavigationViewController();
    if(navc){
        [navc pushViewController:vc animated:YES];
    }else{
        [[YHRouter sharedManager] __errorHandle:YHRouterErrorCodeNavigationNotFound reason:@"没有找到导航控制器"];
    }
}

+ (void)yh_presentViewController:(UIViewController *)vc{
    if(!vc.yh_singleton()){
        return;
    }
    if(!vc.yh_needLogin()){
        return;
    }
    if(!vc){
        return;
    }
    UINavigationController * navc = [[[YHRouter sharedManager].navigationViewClass alloc] initWithRootViewController:vc];
    navc.modalPresentationStyle = UIModalPresentationFullScreen;
    UINavigationController * navcCurrent = YHCurrentNavigationViewController();
    
    __weak typeof(&*vc)weakVC = vc;
    void(^addNavigationCloseItem)(void) = ^(void) {
        UIView * customView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 44, 44)];
        UIButton * closeBtn;
        if (@available(iOS 13.0, *)) {
            closeBtn = [UIButton buttonWithType:UIButtonTypeClose];
        }else{
            closeBtn = [UIButton buttonWithType:UIButtonTypeCustom];
            [closeBtn setTitle:@"关闭" forState:UIControlStateNormal];
            [closeBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
        }
        [closeBtn addActionHandler:^(UIButton *sender, NSInteger tag) {
            weakVC.yh_dismiss();
        }];
        closeBtn.frame = CGRectMake(0, 0, 35, 35);
        closeBtn.center = customView.center;
        [customView addSubview:closeBtn];
        
        weakVC.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:customView];
    };
    addNavigationCloseItem();
    
    if(navcCurrent){
        [navcCurrent presentViewController:navc animated:YES completion:nil];
    }else{
        [YHCurrentViewController() presentViewController:navc animated:YES completion:nil];
    }
}
 

#pragma mark - URL

/// 通过URL跳转 内部含 控制器名称的参数信息
/// mocr://quick?id=12&type=22
+ (UIViewController *)yh_openURL:(NSString *)routePattern{

    NSURLComponents *components = [NSURLComponents componentsWithString:routePattern];
    NSString *scheme = components.scheme;
    
    //scheme规则自己添加
    if([YHRouter sharedManager].urlScheme){
        if (![scheme isEqualToString:[YHRouter sharedManager].urlScheme]) {
            [[YHRouter sharedManager] __errorHandle:YHRouterErrorCodeURLSchemeMismatch reason:[NSString stringWithFormat:@"url中的scheme：%@ 跟自定义的：%@不匹配",scheme,[YHRouter sharedManager].urlScheme]];
            return nil;
        }
    }
    
    NSString * vcHost = nil;
    if (components.host.length > 0 && (![components.host isEqualToString:@"localhost"] && [components.host rangeOfString:@"."].location == NSNotFound)) {
        vcHost = [components.percentEncodedHost copy];
        components.host = @"/";
        components.percentEncodedPath = [vcHost stringByAppendingPathComponent:(components.percentEncodedPath ?: @"")];
    }
    
    NSString *path = [components percentEncodedPath];
    if (components.fragment != nil) {
        BOOL fragmentContainsQueryParams = NO;
        NSURLComponents *fragmentComponents = [NSURLComponents componentsWithString:components.percentEncodedFragment];
        
        if (fragmentComponents.query == nil && fragmentComponents.path != nil) {
            fragmentComponents.query = fragmentComponents.path;
        }
        
        if (fragmentComponents.queryItems.count > 0) {
            fragmentContainsQueryParams = fragmentComponents.queryItems.firstObject.value.length > 0;
        }
        
        if (fragmentContainsQueryParams) {
            components.queryItems = [(components.queryItems ?: @[]) arrayByAddingObjectsFromArray:fragmentComponents.queryItems];
        }
        
        if (fragmentComponents.path != nil && (!fragmentContainsQueryParams || ![fragmentComponents.path isEqualToString:fragmentComponents.query])) {
            path = [path stringByAppendingString:[NSString stringWithFormat:@"#%@", fragmentComponents.percentEncodedPath]];
        }
    }
    
    if (path.length > 0 && [path characterAtIndex:0] == '/') {
        path = [path substringFromIndex:1];
    }
    
    if (path.length > 0 && [path characterAtIndex:path.length - 1] == '/') {
        path = [path substringToIndex:path.length - 1];
    }
    
    //获取queryItem
    NSArray <NSURLQueryItem *> *queryItems = [components queryItems] ?: @[];
    NSMutableDictionary *queryParams = [NSMutableDictionary dictionary];
    for (NSURLQueryItem *item in queryItems) {
        if (item.value == nil) {
            continue;
        }
        
        if (queryParams[item.name] == nil) {
            queryParams[item.name] = item.value;
        } else if ([queryParams[item.name] isKindOfClass:[NSArray class]]) {
            NSArray *values = (NSArray *)(queryParams[item.name]);
            queryParams[item.name] = [values arrayByAddingObject:item.value];
        } else {
            id existingValue = queryParams[item.name];
            queryParams[item.name] = @[existingValue, item.value];
        }
    }
    
    NSDictionary *params = queryParams.copy;
    if(IsNull(vcHost)){
        vcHost = [[YHRouter sharedManager] __queryPageNameAtURLPathParams:params];
    }
    return [YHRouter yh_pushKey:vcHost params:[YHRouterParam params:params, nil]];
}



/// 通过URL跳转 内部含 控制器名称的参数信息
/// https://host?page=helpCenter
+ (UIViewController *)yh_openUniversalLink:(NSString *)routePattern {

    NSURLComponents *components = [NSURLComponents componentsWithString:routePattern];
    
    //获取queryItem
    NSArray <NSURLQueryItem *> *queryItems = [components queryItems] ?: @[];
    NSMutableDictionary *queryParams = [NSMutableDictionary dictionary];
    for (NSURLQueryItem *item in queryItems) {
        if (item.value == nil) {
            continue;
        }
        
        if (queryParams[item.name] == nil) {
            queryParams[item.name] = item.value;
        } else if ([queryParams[item.name] isKindOfClass:[NSArray class]]) {
            NSArray *values = (NSArray *)(queryParams[item.name]);
            queryParams[item.name] = [values arrayByAddingObject:item.value];
        } else {
            id existingValue = queryParams[item.name];
            queryParams[item.name] = @[existingValue, item.value];
        }
    }
    
    NSDictionary *params = queryParams.copy;
    NSString * page = [[YHRouter sharedManager] __queryPageNameAtURLPathParams:params];
    if(IsNull(page)){
        page = [components.path stringByReplacingOccurrencesOfString:@"/" withString:@""];
    }

    return [YHRouter yh_pushKey:page params:[YHRouterParam params:params, nil]];
}


#pragma mark - privite

- (NSString *)__queryPageNameAtURLPathParams:(NSDictionary *)params{
    if(![params isKindOfClass:[NSDictionary class]]){
        return nil;
    }
    if(!self.URLPageKeypaths){
        [[YHRouter sharedManager] __errorHandle:YHRouterErrorCodeConfigIncomplete reason:@"未设置 URLPageKeypaths 信息"];
        return nil;
    }
    for(NSString * key in self.URLPageKeypaths){
        id path = [params objectForKey:key];
        if(path && ![path isKindOfClass:[NSNull class]]){
            return path;
        }
    }
    return nil;
}

- (void)__errorHandle:(YHRouterErrorCode)code reason:(NSString *)reason{
    if(self.errorHandler){
        self.errorHandler(code,reason);
    }
}


@end
